#ifndef TCP_SERVER_H__
#define TCP_SERVER_H__

#include <iostream>
#include <boost/asio.hpp>
#include <string>
#include <unordered_map>
#include "Subscriber.h"

using namespace boost::asio::ip;

// 数据包头
struct NetPacketHeader
{
    char cFlag;          // 数据头的标志——填充‘s’
    long nLenth;         // 要发送的数据大小 由于需要发送文件，因此nlenth值可能很大，所以用long
    char cDataType;      // 接收/发送的数据类型 a-文件列表 b-文件 c-数据文本
    char sFileFormat[4]; // 如果是文件，这里即为文件格式，如果是文本数据，这里用'\0'填充
    char cSendDc;        // 校验码 服务器发包填充-"s"  客户端发包填充-"c"
};

class serviceThreadPool
{
    // 管理io_service的线程池
    // 1.初始化一定数量的io_service，用io_service::work阻塞住，让其不退出
    // 2.让io_service运行在不同的线程里，每来一个客户端，分配一个io_service
    std::vector<std::shared_ptr<boost::asio::io_service>> m_ioServiceList;
    std::vector<std::shared_ptr<boost::asio::io_service::work>> m_workList;
    // std::vector<std::thread> m_threadList;
    int m_poolSize;
    int m_io_service_pos; // 依次分配io_service
public:
    // 在多核的机器上，线程池中的数量最好等于核数
    explicit serviceThreadPool(int pool_size = 4);
    void startPool();
    void stop();
    boost::asio::io_service &get_io_service();
};

class rwhandler
{
#define MSG_HEAD_SIZE 16      // 包头大小
#define RECV_BUFFER_SIZE 1024 // 包头大小
    // 由于读写操作时，socket要与读写操作的递归函数进行绑定，
    // 因此这里单独实现一个读写类，用来处理，每一个连接进来的客户端的读写事件

private:
    tcp::socket m_socket;
    bool m_socket_is_valid;
    unsigned char *m_getData;
    char m_buffer[RECV_BUFFER_SIZE];
    int m_clientId;
    std::function<void(int)> m_callbackError;             // 异常回调函数
    std::function<void(int, std::string)> m_callbackRecv; // 异常回调函数

public:
    explicit rwhandler(boost::asio::io_service &ios);
    ~rwhandler();
    tcp::socket &getSock();
    void read();
    void write(const std::string &message);
    void handle_write(const boost::system::error_code &error, std::size_t);
    void setClientID(int id);
    int getClientID();
    // 应用层，也就是server中利用SetCallBackError设置执行异常回调的函数
    template <typename F>
    void SetCallBackError(F f);
    template <typename F>
    void SetCallBackRecv(F f);
    void handleError(const boost::system::error_code &ec);
};

class server
{
#define MAX_CLINET_NUM 9999 // 最大连接数量

    // 这里利用m_rwIdList去管理客户端的无序表的ID，每次有新客户端连接进来，就从m_rwIdList的头部取一个ID,并将该ID从m_rwIdList中删除
    // 如果有客户端异常或者主动断开，则根据客户端ID去移除无序表中的rwhandle，然后将该ID放回m_rwIdList的尾部
public:
    explicit server(boost::asio::io_service &ios, short port, int serPoolSize = 4);
    ~server();

    void setRecvDataProcessor(std::function<void(int, std::string)> processor);
    void setConnChangedProcessor(std::function<void(int, bool)> processor);

    void sendData(const std::vector<int> &ids, const std::string &buffer);

private:
    // std::vector<std::shared_ptr<rwhandler>> m_rwList;
    // 无序表，用于管理连接来的客户端的读写
    std::unordered_map<int, std::shared_ptr<rwhandler>> m_rwMap;
    std::list<int> m_rwIdList;      // 管理连接进来的客户端的ID（循环用）
    boost::asio::io_service &m_ios; // 这个io_service只用于acceptor
    tcp::acceptor m_acceptor;
    serviceThreadPool m_servicePool;
    std::mutex m_lock;

    std::function<void(int, std::string)> m_vRecvDataProcessor; // 回调转发数据
    std::function<void(int, bool)> m_vConnChangedProcessor;     // 回调转发连接变化

    void accept();
    void reSetRwID(int id);
    size_t getClientNum();
    void recvDataCallback(int id, std::string buffer);
};

#endif